/**

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     licenses@blazegraph.com

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package com.bigdata.journal;

import java.nio.ByteBuffer;

import com.bigdata.btree.BTree;
import com.bigdata.rwstore.RWStore;
import com.bigdata.rwstore.sector.MemoryManager;

/**
 * <p>
 * The buffer mode in which the journal is opened.
 * </p>
 * <p>
 * The {@link #Direct} and {@link #Mapped} options may not be used for files
 * exceeding {@link Integer#MAX_VALUE} bytes in length since a
 * {@link ByteBuffer} is indexed with an <code>int</code> (the pragmatic limit
 * is typically much lower and depends on the size of the JVM heap for the
 * {@link #Direct} mode).
 * </p>
 * 
 * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
 * @version $Id$
 */
public enum BufferMode {

    /**
     * <p>
     * A variant on the {@link #Direct} mode that is not restart-safe. This mode
     * is useful for temporary stores which can reside entirely in memory and do
     * not require disk.  It can be used in environments, such as an applet,
     * where you can not access the disk (however, you can also use a transient
     * {@link BTree} with much the same effect).  The {@link #Temporary} mode
     * is much more scalable.
     * </p>
     * 
     * @see TransientBufferStrategy
     */
    Transient(false/* stable */, true/* fullyBuffered */,
            Options.MEM_MAX_EXTENT, StoreTypeEnum.WORM),

    /**
     * <strong>This mode is not being actively developed and should not be used
     * outside of unit tests.</strong>
     * <p>
     * A direct buffer is allocated for the file image. Writes are applied to
     * the buffer. The buffer tracks dirty slots regardless of the transaction
     * that wrote them and periodically writes dirty slots through to disk. On
     * commit, any dirty index or allocation nodes are written onto the buffer
     * and all dirty slots on the buffer. Dirty slots in the buffer are then
     * synchronously written to disk, the appropriate root block is updated, and
     * the file is (optionally) flushed to disk.
     * </p>
     * <p>
     * This option wires an image of the journal file into memory and
     * allows the journal to optimize IO operations.
     * </p>
     * 
     * @see DirectBufferStrategy
     */
    Direct(true/* stable */, true/* fullyBuffered */, Options.MEM_MAX_EXTENT,
            StoreTypeEnum.WORM),

    /**
     * <strong>This mode is not being actively developed and should not be used
     * outside of unit tests. Memory mapped IO has the fatal weakness under Java
     * that you can not reliably close or extend the backing file.</strong>
     * <p>
     * A memory-mapped buffer is allocated for the file image. Writes are
     * applied to the buffer. Reads read from the buffer. On commit, the map is
     * forced disk disk.
     * </p>
     * <p>
     * This option yields control over IO and memory resources to the OS.
     * However, there is currently no way to force release of the mapped memory
     * per the bug described below. This means (a) you might not be able to
     * delete the mapped file; and (b) that native memory can be exhausted.
     * While performance is good on at least some benchmarks, it is difficult to
     * recommend this solution given its downsides.
     * </p>
     * 
     * @see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038
     * @see MappedBufferStrategy
     */
    Mapped(true/* stable */, false/* fullyBuffered */,
            Options.OTHER_MAX_EXTENT, StoreTypeEnum.WORM),

    /**
     * <p>
     * This is a synonym for {@link #DiskWORM}.
     * </p>
     * 
     * @see WORMStrategy
     */
    Disk(true/* stable */, false/* fullyBuffered */, Options.OTHER_MAX_EXTENT,
            StoreTypeEnum.WORM),

    /**
     * <p>
     * The journal is managed on disk. This option may be used with files of
     * more than {@link Integer#MAX_VALUE} bytes in extent. Journal performance
     * for large files should be fair on write, but performance will degrade as
     * the journal is NOT optimized for random reads (poor locality).
     * </p>
     * 
     * @see WORMStrategy
     */
    DiskWORM(true/* stable */, false/* fullyBuffered */,
            Options.OTHER_MAX_EXTENT, StoreTypeEnum.WORM),

    /**
     * <p>
     * The journal is managed on disk. This option may be used with files of
     * more than {@link Integer#MAX_VALUE} bytes in extent. RW indicates that
     * it is not a WORM with append only semantics but rather a disk alloc/realloc
     * mechanism that supports updates to values.  In general the store locality
     * may be poor but should normally benefit in comparison to a WORM with
     * smaller disk size.
     * </p>
     * 
     * @see RWStrategy
     */
    DiskRW(true/* stable */, false/* fullyBuffered */, Options.RW_MAX_EXTENT,
            StoreTypeEnum.RW),

    /**
     * <p>
     * A variant on the DiskRW backed by a temporary file.  Options enable
     * part of the store to be held with Direct ByteBuffers.  A significant
     * use case would be an in-memory store but with disk overflow if
     * required.
     * </p>
     * 
     * @see RWStrategy
     */
    TemporaryRW(false/* stable */, false/* fullyBuffered */,
            Options.RW_MAX_EXTENT, StoreTypeEnum.RW),

    /**
     * <p>
     * A variant on the {@link #Disk} mode that is not restart-safe. This mode
     * is useful for all manners of temporary data with full concurrency control
     * and scales-up to very large temporary files. The backing file (if any) is
     * always destroyed when the store is closed. This is much more scalable
     * than the {@link #Transient} mode.
     * </p>
     * 
     * @see DiskOnlyStrategy
     */
    Temporary(false/* stable */, false/* fullyBuffered */,
            Options.OTHER_MAX_EXTENT, StoreTypeEnum.WORM),

    /**
     * A transient buffer mode backed by the {@link MemoryManager}, which is
     * similar to the {@link RWStore} but optimized for main memory. This can
     * scale up to 4TB of main memory.
     */
    MemStore(false/* stable */, true/* fullyBuffered */,
            Options.RW_MAX_EXTENT, StoreTypeEnum.RW)

    ;

    private final boolean stable;
    private final boolean fullyBuffered;
    private final long maxExtent;

    private final StoreTypeEnum storeType;

    private BufferMode(final boolean stable, final boolean fullyBuffered,
            final long maxExtent,
            final StoreTypeEnum storeType) {

        this.stable = stable;

        this.fullyBuffered = fullyBuffered;
        
        this.maxExtent = maxExtent;

        this.storeType = storeType;
        
    }
    
    /**
     * <code>true</code> iff this {@link BufferMode} uses a stable media
     * (disk).
     */
    public boolean isStable() {
       
        return stable;
        
    }
    
    /**
     * <code>true</code> iff this {@link BufferMode} is fully buffered in
     * memory.
     */
    public boolean isFullyBuffered() {
       
        return fullyBuffered;
        
    }

    /**
     * The maximum extent for the {@link BufferMode}.
     */
    public long getMaxExtent() {
        
        return maxExtent;
        
    }
    
    /**
     * The kind of persistence store (RW or WORM).
     * 
     * @see StoreTypeEnum
     */
    public StoreTypeEnum getStoreType() {

        return storeType;
        
    }
    
    public static BufferMode getDefaultBufferMode(final StoreTypeEnum storeType) {
        switch (storeType) {
    	case RW:
    		return DiskRW;
    	default:
    		return DiskWORM;
    	}    	
    }

}
